package com.niiwoo.civet.trade.service.dubbo.project;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.niiwoo.activity.stage.dto.request.prize.ActivityPrizeResetStatusReqDTO;
import com.niiwoo.activity.stage.service.prize.ActivityPrizeDubboService;
import com.niiwoo.asset.cardniu.dto.request.LoanApplyOrderDTO;
import com.niiwoo.asset.cardniu.service.loan.FlowExecuteDubboService;
import com.niiwoo.asset.cardniu.service.loan.LoanDubboService;
import com.niiwoo.asset.constant.MqConstants;
import com.niiwoo.asset.dto.mq.R360OrderStatusChangedDTO;
import com.niiwoo.asset.enums.r360.R360OrderProjectSubStatusEnum;
import com.niiwoo.asset.enums.r360.R360OrderStatusEnum;
import com.niiwoo.civet.trade.dao.entity.Project;
import com.niiwoo.civet.trade.dao.entity.ProjectBackoutBorrowPrize;
import com.niiwoo.civet.trade.dao.entity.ProjectBorrowerSummary;
import com.niiwoo.civet.trade.dao.entity.ProjectLoanDeviceInfo;
import com.niiwoo.civet.trade.dao.mapper.ProjectMapperExt;
import com.niiwoo.civet.trade.dto.Tuple2;
import com.niiwoo.civet.trade.dto.common.ProjectAndBorrowerPlanDTO;
import com.niiwoo.civet.trade.dto.common.ProjectBorrowerSummaryDTO;
import com.niiwoo.civet.trade.dto.common.ProjectDTO;
import com.niiwoo.civet.trade.dto.common.ProjectDynamicDTO;
import com.niiwoo.civet.trade.dto.request.*;
import com.niiwoo.civet.trade.dto.request.loan.CardniuLoanApplyOrderDTO;
import com.niiwoo.civet.trade.dto.response.CurrentPeriodToReturnDTO;
import com.niiwoo.civet.trade.dto.response.CustomSysBorrowerInfoDTO;
import com.niiwoo.civet.trade.dto.response.ProjectDetailDTO;
import com.niiwoo.civet.trade.dto.response.QueryLoanDeviceInfoResponseDTO;
import com.niiwoo.civet.trade.dto.response.SpeedLoanRecordStatisticsDTO;
import com.niiwoo.civet.trade.dto.response.newRefund.RefundFreezeParamResponseDTO;
import com.niiwoo.civet.trade.enums.*;
import com.niiwoo.civet.trade.service.dubbo.loan.SpeedLoanDubboServiceImpl;
import com.niiwoo.civet.trade.service.local.common.ProjectCommonService;
import com.niiwoo.civet.trade.service.local.configure.TradeConfigLocalService;
import com.niiwoo.civet.trade.service.local.loan.ProjectBackoutBorrowPrizeService;
import com.niiwoo.civet.trade.service.local.loan.SpeedLoanService;
import com.niiwoo.civet.trade.service.local.project.ProjectLocalService;
import com.niiwoo.civet.trade.service.project.ProjectDubboService;
import com.niiwoo.civet.user.dto.request.AppButtonDTO;
import com.niiwoo.civet.user.dto.request.UserLetterRequestDTO;
import com.niiwoo.civet.user.enums.MessageTemplateKeyEnum;
import com.niiwoo.civet.user.enums.SMSTemplateKeyEnum;
import com.niiwoo.civet.user.enums.TianchengCallbackEventEnum;
import com.niiwoo.civet.user.enums.UserLetterTypeEnum;
import com.niiwoo.civet.user.service.*;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import com.niiwoo.tripod.tiancheng.component.TianchengAgainstFakeService;
import com.niiwoo.tripod.tiancheng.component.TianchengAgainstFakeV2Service;
import com.niiwoo.tripod.tiancheng.enums.FunctionCodeEnum;
import com.niiwoo.tripod.tiancheng.request.afp.RiskRuleRequest;
import com.niiwoo.tripod.tiancheng.response.common.RiskRuleResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service(version = "1.0.0")
public class ProjectDubboServiceImpl implements ProjectDubboService {
    // 天秤授信反欺诈回调地址模型(AFP)
    public static final String TIANCHENG_AFP_CALLBACK_URL = "%s/tc/%s/%s/callback?functionCode=%s";
    //卡牛风险规则回调地址模型
    public static final String TIANCHENG_CARDNIU_AFP_CALLBACK_URL = "%s/tc/%s/%s/cardniuCallback?functionCode=%s";
    public static final String LOAN_QUANTITY_LIMIT_KEY = "loan_quantity_limit";
    @Value(value = "${web-http-url}")
    private String webHttpUrl;
    @Value("${h5-borrow-detail-url}")
    private String h5BorrowDetailUrl;
    @Autowired
    private ProjectLocalService projectLocalService;

    @Autowired
    private TradeConfigLocalService tradeConfigService;

    @Autowired
    private ProjectCommonService projectCommonService;

    @Reference(version = "1.0.0")
    private ActivityPrizeDubboService activityPrizeDubboService;

    @Autowired
    ProjectBackoutBorrowPrizeService projectBackoutBorrowPrizeService;
    @Reference(version = "1.0.0")
    private UserLetterDubboService userLetterDubboService;

    @Reference(version = "1.0.0")
    private SendSmsDubboService sendSmsDubboService;

    @Reference(version = "1.0.0")
    private UserBasicInfoDubboService userBasicInfoDubboService;
    @Reference(version = "1.0.0")
    private UserIdentityDubboService userIdentityDubboService;
    @Reference(version = "1.0.0")
    private UserDataDubboService userDataDubboService;
    @Reference(version = "1.0.0")
    private UserAuthorizationInfoDubboService userAuthorizationInfoDubboService;
    @Reference(version = "1.0.0")
    private FlowExecuteDubboService flowExecuteDubboService;
    @Reference(version = "1.0.0")
    private LoanDubboService loanDubboService;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    PrivacyMasks privacyMasks;
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private TianchengAgainstFakeV2Service tianchengAgainstFakeV2Service;
    @Autowired
    private TianchengAgainstFakeService tianchengAgainstFakeService;
    @Autowired
    private SpeedLoanService loanLocalService;

    @Autowired
    private ProjectMapperExt projectMapper;

    @Override
    public ProjectDTO selectProjectById(Long projectId) {
        Assert.notNull(projectId, "projectId is null");
        return projectLocalService.selectProjectById(projectId);
    }

    @Override
    public ProjectAndBorrowerPlanDTO selectProjectAndPlanByProjectIdAndPeriod(Long projectId, Integer period) {
        Assert.notNull(projectId, "projectId is null");
        Assert.notNull(period, "period is null");
        return projectLocalService.selectProjectAndPlanByProjectIdAndPeriod(projectId, period);
    }

    /**
     * 根据标的ID查询提现状态
     *
     * @param projectId
     * @return 状态枚举
     * 0:预提交（初始状态，等待用户存管页面操作结果）
     * 1:待确认（收到存管页面操作成功，等待你我金融复核通过后确认/取消提现操作）
     * 2:出款中 （复核通过调用确认提现成功后，等待存管系统出款 )
     * 3:提现成功（已接受到存管系统提现成功异步通知）
     * 4:提现失败（已接收到存管系统提现失败异步通知/审核不通过调用取消提现接口成功后）
     * 5:已关闭 (定时任务扫到超过存管页面过期时间且调用存管接口查询订单不存在的会更新为过期状态)
     */
    @Override
    public Byte selectProjectLendRecordByProjectId(Long projectId) {
        Assert.notNull(projectId, "projectId is null");
        return projectLocalService.selectProjectLendRecordByProjectId(projectId);
    }


    /**
     * 查询极速借记录统计信息
     *
     * @param userId
     * @return
     */
    @Override
    public SpeedLoanRecordStatisticsDTO querySpeedLoanRecordStatistics(String userId) {
        return projectLocalService.querySpeedLoanRecordStatistics(userId);
    }

    /**
     * 用户换绑银行卡后给资产端发MQ
     */
    @Override
    public void sendMqToAssetSide(String userId) {
        Assert.notNull(userId, "userId is null");
        projectLocalService.sendMqToAssetSide(userId);
    }

    @Override
    public QueryLoanDeviceInfoResponseDTO queryLoanDeviceInfo(Long projectId) {
        return transQueryLoanDeviceInfo2DTO(projectCommonService.queryLoanDeviceInfo(projectId));
    }

    private QueryLoanDeviceInfoResponseDTO transQueryLoanDeviceInfo2DTO(ProjectLoanDeviceInfo projectLoanDeviceInfo) {
        QueryLoanDeviceInfoResponseDTO queryLoanDeviceInfoResponseDTO = new QueryLoanDeviceInfoResponseDTO();
        queryLoanDeviceInfoResponseDTO.setProjectId(projectLoanDeviceInfo.getProjectId());
        queryLoanDeviceInfoResponseDTO.setUserId(projectLoanDeviceInfo.getUserId());
        queryLoanDeviceInfoResponseDTO.setDeviceId(projectLoanDeviceInfo.getDeviceId());
        queryLoanDeviceInfoResponseDTO.setOs(projectLoanDeviceInfo.getOs());
        queryLoanDeviceInfoResponseDTO.setBrandType(projectLoanDeviceInfo.getBrandType());
        queryLoanDeviceInfoResponseDTO.setDsds(projectLoanDeviceInfo.getDsds());
        queryLoanDeviceInfoResponseDTO.setDeviceStatus(projectLoanDeviceInfo.getDeviceStatus());
        queryLoanDeviceInfoResponseDTO.setGps(projectLoanDeviceInfo.getGps());
        queryLoanDeviceInfoResponseDTO.setIp(projectLoanDeviceInfo.getIp());
        queryLoanDeviceInfoResponseDTO.setNetwork(projectLoanDeviceInfo.getNetwork());
        queryLoanDeviceInfoResponseDTO.setWifiSsid(projectLoanDeviceInfo.getWifiSsid());
        queryLoanDeviceInfoResponseDTO.setBlackBox(projectLoanDeviceInfo.getBlackBox());
        queryLoanDeviceInfoResponseDTO.setCreateTime(projectLoanDeviceInfo.getCreateTime());
        queryLoanDeviceInfoResponseDTO.setUpdateTime(projectLoanDeviceInfo.getUpdateTime());

        return queryLoanDeviceInfoResponseDTO;
    }


    /**
     * 流标
     */
    @Override
    public void flow(ProjectFlowRequestDTO requestDTO) {
        log.info("流标###请求###projectId={}, data={}", requestDTO.getProjectId(), JSON.toJSONString(requestDTO));
        /**
         *  //5已流标
         MISCARRY_AUTO_FAILED(500,"流标-自动审核不通过",ProjectStatusEnum.MISCARRY,""),
         MISCARRY_MANUAL_FAILED(501,"流标-人工审核不通过",ProjectStatusEnum.MISCARRY,""),
         MISCARRY_BACK_OVERTIME(502,"流标-借款退回超时未处理",ProjectStatusEnum.MISCARRY,"你的借款资料不完善，请完善后再次提交"),
         MISCARRY_CANCER_BORROWER(503,"流标-借款人手动取消",ProjectStatusEnum.MISCARRY,""),
         MISCARRY_INVEST_OVERTIME(504,"流标-投资超时",ProjectStatusEnum.MISCARRY,""),
         MISCARRY_CANCER_MANAGER(505,"流标-管理人员手动取消",ProjectStatusEnum.MISCARRY,""),
         MISCARRY_LOAN_FAKE_FAILED(506,"流标-借款反欺诈不通过",ProjectStatusEnum.MISCARRY,""),
         MISCARRY_LOAN_BATCH(507,"管理员批量流标",ProjectStatusEnum.MISCARRY,""),
         MISCARRY_PUSH_FAIL(508,"存管上标失败",ProjectStatusEnum.MISCARRY,""),
         */
        if (requestDTO.getSubStatus() != null && requestDTO.getSubStatus().getParentStatusEnum() != ProjectStatusEnum.MISCARRY) {
            log.error("流标###失败，projectId={}, subStatus={}", requestDTO.getProjectId(), requestDTO.getSubStatus().name());
            throw new BizException("TRD90001");
        }
        Tuple2<Boolean, ProjectBackoutBorrowPrize> t = projectLocalService.flow(requestDTO);
        // 更新标的成功
        if (t.get_1()) {
            log.info("流标###成功，projectId={}, subStatus={}", requestDTO.getProjectId(), requestDTO.getSubStatus().name());
            // 处理借款红包
            if (t.get_2() != null) {
                // 异步调用
                CompletableFuture.supplyAsync(() -> {
                    ActivityPrizeResetStatusReqDTO reqDTO = new ActivityPrizeResetStatusReqDTO();
                    reqDTO.setPrizeId(t.get_2().getPrizeId());
                    reqDTO.setUserId(t.get_2().getUserId());
                    log.info("流标###退回借款红包###请求, projectId={}, request={}", t.get_2().getProjectId(), JSON.toJSONString(reqDTO));
                    activityPrizeDubboService.resetPrizeToReturned(reqDTO);
                    return true;
                }).whenComplete((success, throwable) -> {
                    if (throwable != null) {
                        log.error(String.format("流标###退回借款红包###异常, projectId=%s,, errorMessage=%s", t.get_2().getProjectId(), throwable.getMessage()), throwable);
                    } else {
                        // 退回成功，更新记录状态
                        log.info("流标###退回借款红包###成功，删除退回记录, projectId={}, response={}", t.get_2().getProjectId(), success);
                        projectBackoutBorrowPrizeService.del(t.get_2().getProjectId());
                    }
                });
            }

            // 通知资产端
            CompletableFuture.runAsync(() -> notifyAssetForR360(requestDTO.getProjectId()));

        } else {
            log.error("流标###失败，projectId={}, subStatus={}", requestDTO.getProjectId(), requestDTO.getSubStatus().name());
            throw new BizException("TRD90001");
        }
    }

    private void notifyAssetForR360(Long projectId){

        if (projectId == null) {
            return;
        }
        try {
            Project project = projectMapper.selectByPrimaryKey(projectId);
            if (project == null) {
                return;
            }

            if (project.getSubStatus() != null && (project.getSubStatus() == R360OrderProjectSubStatusEnum.MISCARRY_CANCER_MANAGER.getSubStatus() || project.getSubStatus() == R360OrderProjectSubStatusEnum.MISCARRY_LOAN_BATCH.getSubStatus())) {
                if (project.getFromSource() != null && project.getFromSource().byteValue() == ProjectFromSourceEnum.R360.getType()) {
                    R360OrderStatusChangedDTO r360OrderStatusChangedDTO = new R360OrderStatusChangedDTO();
                    r360OrderStatusChangedDTO.setProjectId(project.getProjectId());
                    r360OrderStatusChangedDTO.setR360OrderStatusEnumCode(R360OrderStatusEnum.LOAN_CANCEL.getCode());
                    r360OrderStatusChangedDTO.setR360OrderProjectSubStatusEnum(R360OrderProjectSubStatusEnum.enumOf(project.getSubStatus()));
                    r360OrderStatusChangedDTO.setUpdateDate(new Date());
                    rabbitTemplate.convertAndSend(MqConstants.Exchange.ASSET_EXCHANGE, MqConstants.getRoutingKey(MqConstants.Exchange.ASSET_EXCHANGE, MqConstants.Queue.ORDER_STATUS_NOFIFY_FOR_COMMON),
                            r360OrderStatusChangedDTO);
                    log.info("融360标流标通知资产端成功，projectId:{}", project.getProjectId());
                }
            }
        } catch (Exception e) {
            log.error("融360标流标通知资产端失败，projectId:{}", projectId, e);
        }
    }

    @Override
    public void r360TimeoutUnconfirmedFlow() {
        Long beginTime = System.currentTimeMillis();
        log.info("融360标的借款超时未确认自动流标任务开始");

        // 确认借款超时时间，默认24小时
        Integer confirmLoanTimeout = 24;
        String sureTimeConfigValue = tradeConfigService.selectTradeConfigByEmun(TradeConfigEnum.LOAN_RONG360SURETIME);
        if (!StringUtils.isEmpty(sureTimeConfigValue)) {
            confirmLoanTimeout = Integer.valueOf(sureTimeConfigValue);
        }
        log.info("融360标的借款超时未确认自动流标，查询符合条件的标的数据，当前配置超时时间：{}H", confirmLoanTimeout);

        // 查询数据
        List<Project> projectList = projectLocalService.getR360TimeoutUnconfirmedProjectList(confirmLoanTimeout);
        if (CollectionUtils.isEmpty(projectList)) {
            log.info("融360标的借款超时未确认自动流标， 当前符合条件的标，任务结束");
            return;
        }

        // 记录处理结果
        int successNum = 0;
        int failureNum = 0;

        // 循环处理项目流标
        for (Project project : projectList) {
            ProjectFlowRequestDTO requestDTO = new ProjectFlowRequestDTO();
            requestDTO.setProjectId(project.getProjectId());
            requestDTO.setSubStatus(ProjectSubStatusEnum.MISCARRY_R360_TIMEOUT_UNCONFIRMED);
            requestDTO.setRemark("融360标的超时未确认借款流标");
            Tuple2<Boolean, ProjectBackoutBorrowPrize> t = projectLocalService.flow(requestDTO);

            if (t.get_1()) {
                log.info("融360标的借款超时未确认自动流标，流标成功，projectId={}, subStatus={}", requestDTO.getProjectId(), requestDTO.getSubStatus().name());

                R360OrderStatusChangedDTO r360OrderStatusChangedDTO = new R360OrderStatusChangedDTO();
                r360OrderStatusChangedDTO.setProjectId(project.getProjectId());
                r360OrderStatusChangedDTO.setR360OrderStatusEnumCode(R360OrderStatusEnum.LOAN_CANCEL.getCode());
                r360OrderStatusChangedDTO.setR360OrderProjectSubStatusEnum(R360OrderProjectSubStatusEnum.MISCARRY_R360_TIMEOUT_UNCONFIRMED);
                r360OrderStatusChangedDTO.setUpdateDate(new Date());
                rabbitTemplate.convertAndSend(MqConstants.Exchange.ASSET_EXCHANGE, MqConstants.getRoutingKey(MqConstants.Exchange.ASSET_EXCHANGE, MqConstants.Queue.ORDER_STATUS_NOFIFY_FOR_COMMON),
                        r360OrderStatusChangedDTO);

                log.info("融360标的借款超时未确认自动流标，流标成功发送MQ消息通知融资产端标的状态变更，消息内容：{}", JSONObject.toJSONString(r360OrderStatusChangedDTO));
                successNum++;
            } else {
                log.error("融360标的借款超时未确认自动流标，流标失败，projectId={}, subStatus={}", requestDTO.getProjectId(), requestDTO.getSubStatus().name());
                failureNum++;
            }
        }
        log.info("融360标的借款超时未确认自动流标，自动流标任务结束，总处理标的个数:{}，其中处理成功：{}, 失败：{}. 总耗时：{}ms", projectList.size(), successNum, failureNum, System.currentTimeMillis() - beginTime);
    }

    @Override
    public void addProjectDynamicRecord(ProjectDynamicDTO projectDynamicDTO) {
        Assert.notNull(projectDynamicDTO, "对象不可空");
        Assert.notNull(projectDynamicDTO.getProjectId(), "标的不可空");
        Assert.notNull(projectDynamicDTO.getUserId(), "用户id不可空");
        Assert.notNull(projectDynamicDTO.getTradeTypeEnum(), "交易类型不可空");
        projectLocalService.addProjectDynamicRecord(projectDynamicDTO);
    }

    @Override
    public void r360Back(ProjectBackRequestDTO reqDTO) {
        log.info("标的退回，projectId={}, subStatus={}", reqDTO.getProjectId(), reqDTO.getSubStatus().name());
        projectLocalService.back(reqDTO);
    }

    /**
     * 退回
     */
    @Override
    public void back(ProjectBackRequestDTO reqDTO) {
        log.info("标的退回，projectId={}, subStatus={}", reqDTO.getProjectId(), reqDTO.getSubStatus().name());
        projectLocalService.back(reqDTO);
        //短信未调用 极光推送、通知
        //todo luosiwen 短信未调用 极光推送、通知
        ProjectDTO projectDTO = projectLocalService.selectProjectById(reqDTO.getProjectId());
        boolean isCardLoan = projectDTO.getType().equals(com.niiwoo.civet.trade.enums.ProjectTypeEnum.CARD_NIU_LOAN.getValue());
        boolean isFormCardNiu = projectDTO.getFromSource().equals(ProjectFromSourceEnum.CARD_NIU.getType());
        if (isCardLoan && isFormCardNiu) {
            //设置参数
            List<Object> smsTemplateParamList = new ArrayList<Object>();
            smsTemplateParamList.add(reqDTO.getReason());
            //发送短信服务
            sendSmsDubboService.sendSmsByUserId(reqDTO.getBorrowerUserId(), SMSTemplateKeyEnum.CARD_NIU_TEMP_SPEEDLOAN_MANUAL_BACK.getKey(), smsTemplateParamList);
        } else {
            //极光推送+通知
            UserLetterRequestDTO userLetterRequestDTO = new UserLetterRequestDTO();
            userLetterRequestDTO.setUserLetterTypeEnum(UserLetterTypeEnum.LETTER_AND_JPUSH);
            //退回枚举
            userLetterRequestDTO.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.SPEED_LOAN_MANUAL_BACK);
            //退回枚举
            userLetterRequestDTO.setJpushTemplateKeyEnum(MessageTemplateKeyEnum.JPushTemplateKeyEnum.SPEED_LOAN_MANUAL_BACK);
            //设置参数
            List<Object> letterTemplateParamList = new ArrayList<Object>();
            letterTemplateParamList.add(reqDTO.getProjectId());
            letterTemplateParamList.add(reqDTO.getTitle());
            letterTemplateParamList.add(reqDTO.getReason());
            //设置参数
            List<Object> jpushTemplateParamList = new ArrayList<Object>();
            jpushTemplateParamList.add(reqDTO.getProjectId());
            jpushTemplateParamList.add(reqDTO.getTitle());
            jpushTemplateParamList.add(reqDTO.getReason());
            //设置参数
            List<Object> smsTemplateParamList = new ArrayList<Object>();
            smsTemplateParamList.add(reqDTO.getReason());
            List<AppButtonDTO> appButtonDTOS = new ArrayList<>();
            // 按钮列表  钱小二、借款详情
            AppButtonDTO appButtonDTO = new AppButtonDTO();
            appButtonDTO.setButtonType(AppButtonDTO.ButtonTypeEnum.MONEY_2);
            appButtonDTO.setLabel(AppButtonDTO.ButtonTypeEnum.MONEY_2.getDesc());

            AppButtonDTO appButtonDTO2 = new AppButtonDTO();
            appButtonDTO2.setButtonType(AppButtonDTO.ButtonTypeEnum.MONMY_LOAN_DETAILEY_2);
            appButtonDTO2.setLabel(AppButtonDTO.ButtonTypeEnum.MONMY_LOAN_DETAILEY_2.getDesc());
            Map<String, Object> params = new HashMap<>();
            params.put("ProjectId", reqDTO.getProjectId());
            params.put("LoadServerUrl", h5BorrowDetailUrl + reqDTO.getProjectId());
            appButtonDTO2.setParams(params);


            appButtonDTOS.add(appButtonDTO);
            appButtonDTOS.add(appButtonDTO2);

            userLetterRequestDTO.setLetterTemplateParamList(letterTemplateParamList);
            userLetterRequestDTO.setJpushTemplateParamList(jpushTemplateParamList);
            userLetterRequestDTO.setProjectId(reqDTO.getProjectId());
            userLetterRequestDTO.setToUserId(reqDTO.getBorrowerUserId());
            userLetterRequestDTO.setLetterButtonList(appButtonDTOS);
            log.info("退回消息推送,userLetterRequestDTO:{}", JSON.toJSONString(userLetterRequestDTO));
            userLetterDubboService.pushLetter(userLetterRequestDTO);
            //发送短信服务
            sendSmsDubboService.sendSmsByUserId(reqDTO.getBorrowerUserId(), SMSTemplateKeyEnum.TEMP_SPEEDLOAN_MANUAL_BACK.getKey(), smsTemplateParamList);
        }

    }

    /**
     * 通过待确认
     */
    @Override
    public void confirm(ProjectConfirmRequestDTO reqDTO) {
        log.info("标的通过待确认，projectId={}, subStatus={}", reqDTO.getProjectId(), reqDTO.getSubStatus().name());
        projectLocalService.confirm(reqDTO);
    }

    /**
     * 查询在审核状态中的某一时间区间的标列表
     *
     * @param endDate
     * @return
     */
    @Override
    public List<ProjectDTO> queryAuthNotifyAuditProjectList(Date endDate) {
        List<Project> list = projectCommonService.queryAuthNotifyAuditProjectList(endDate);
        if (list == null) {
            return null;
        }
        List<ProjectDTO> returnList = new ArrayList<>();
        for (Project project : list) {
            ProjectDTO projectDTO = new ProjectDTO();
            projectDTO.setProjectId(project.getProjectId());
            projectDTO.setBorrowUserId(project.getBorrowUserId());
            projectDTO.setSubmitTime(project.getSubmitTime());
            returnList.add(projectDTO);
        }
        return returnList;
    }

    /**
     * 查询审核中和投资中标的数量
     *
     * @param userId
     * @param fromSourceEnum
     * @return
     */
    @Override
    public Integer countProjectNumInApproveAndInvest(String userId, ProjectFromSourceEnum fromSourceEnum) {
        Assert.notNull(userId, "用户id不能为空");
        Integer totalProjectNumInApproveAndInvest = projectLocalService.countProjectNumInApproveAndInvest(userId, fromSourceEnum);
        return totalProjectNumInApproveAndInvest;
    }

    @Override
    public Integer queryInAuditProjectCount(String userId) {
        return projectLocalService.queryInAuditProjectCount(userId);
    }

    @Override
    public Integer queryProjectCountByUserId(String userId,String orgId) {
        return projectLocalService.queryProjectCountByUserIdAndOrgId(userId,orgId);
    }

    @Override
    public Integer queryProjectCountByUserId(String userId) {
        return projectLocalService.queryProjectCountByUserId(userId);
    }

    @Override
    public ProjectDTO queryLastProjectByUserId(String userId) {
        Project project = projectLocalService.queryLastProjectByUserId(userId);
        ProjectDTO projectDTO = null;
        if (project != null) {
            projectDTO = new ProjectDTO();
            try {
                BeanUtils.copyProperties(projectDTO, project);
            } catch (Exception e) {
                log.error("查询用户最近一次借款记录,用户ID={},发生异常,错误信息={}", e);
            }
        }
        return projectDTO;
    }

    @Override
    public BigDecimal queryTotalInterestByProjectId(Long projectId) {
        return projectLocalService.queryTotalInterestByProjectId(projectId);
    }

    @Override
    public Integer queryLoaningProjectCount(String userId) {
        return projectLocalService.queryLoaningProjectCount(userId);
    }

    @Override
    public ProjectBorrowerSummaryDTO queryDueProjectBorrowerSummaryByProjectId(Long projectId) {
        ProjectBorrowerSummaryDTO projectBorrowerSummaryDTO = null;
        ProjectBorrowerSummary projectBorrowerSummary = projectLocalService.queryDueProjectBorrowerSummaryByProjectId(projectId);
        if (projectBorrowerSummary != null) {
            projectBorrowerSummaryDTO = new ProjectBorrowerSummaryDTO();

            try {
                BeanUtils.copyProperties(projectBorrowerSummaryDTO, projectBorrowerSummary);
            } catch (Exception e) {
                log.error("查询还款计划摘要列表,标的ID={},发生系统异常,原因={}", projectId, e);
            }
        }

        return projectBorrowerSummaryDTO;
    }

    @Override
    public Integer queryLoanSuccessCount(String userId) {
        return projectLocalService.queryLoanSuccessCount(userId);
    }

    @Override
    public CurrentPeriodToReturnDTO queryCurrentPeriodToReturnByProjectId(Long projectId) {
        Assert.notNull(projectId, "标的ID不能为空");
        CurrentPeriodToReturnDTO currentPeriodToReturnDTO = null;
        try {
            currentPeriodToReturnDTO = projectLocalService.queryCurrentPeriodToReturnByProjectId(projectId);
        } catch (Exception e) {
            log.error("queryCurrentPeriodToReturnByProjectId方法发生系统异常,标的ID={},原因={}", projectId, e);
            throw e;
        }
        return currentPeriodToReturnDTO;
    }

    /**
     * 查询符合状态的标的
     *
     * @param userId
     * @param subStatus
     * @return
     */
    @Override
    public Integer findProjectByStatus(String userId, List<Byte> subStatus) {
        return projectLocalService.findProjectByStatus(userId, subStatus);
    }

    /**
     * 卡牛标的初始化
     *
     * @param cardniuProjectDTO
     */
    @Override
    public Long cardNiuProject(CardniuProjectDTO cardniuProjectDTO) {
        return projectLocalService.cardNiuProject(cardniuProjectDTO);
    }

    /**
     * 卡贷风险规则发起
     *
     * @param cardniuLoanApplyOrderDTO
     */
    @Override
    public void startRiskInfo(CardniuLoanApplyOrderDTO cardniuLoanApplyOrderDTO) {
        //发起风险规则流程
        log.info("卡牛风险规则发起projectId={},userId={}", cardniuLoanApplyOrderDTO.getProjectId(), cardniuLoanApplyOrderDTO.getUserId());
        LoanApplyOrderDTO loanApplyOrderDTO = new LoanApplyOrderDTO();
        org.springframework.beans.BeanUtils.copyProperties(cardniuLoanApplyOrderDTO, loanApplyOrderDTO);
        Long flowExecuteId = loanDubboService.createLoanFlowInfo(loanApplyOrderDTO);
        log.info("风险规则流程id= {}",flowExecuteId);
        //触发天称风险规则;
        RiskRuleRequest riskRuleRequest = new RiskRuleRequest();
        riskRuleRequest.setTransDate(new Date());
        riskRuleRequest.setTransNo(String.valueOf(snowflakeIdWorker.nextId()));
        riskRuleRequest.setProjectId(String.valueOf(cardniuLoanApplyOrderDTO.getProjectId()));
        riskRuleRequest.setUserId(cardniuLoanApplyOrderDTO.getUserId());
        riskRuleRequest.setIdentityCard(cardniuLoanApplyOrderDTO.getIdCard());
        String mobile  = cardniuLoanApplyOrderDTO.getMobileNo();
        if (!StringUtils.isEmpty(mobile)) {
            mobile = privacyMasks.decryptPrivacy(mobile);
            riskRuleRequest.setMobilePhone(mobile);
        }
        riskRuleRequest.setRealName(cardniuLoanApplyOrderDTO.getName());
        riskRuleRequest.setFunctionCode(FunctionCodeEnum.LIBRA_FRAUD_RISK_RULE.getBodyFunctionCode());
        riskRuleRequest.setIsNeedDetail(0);
        riskRuleRequest.setCallUrl(String.format(TIANCHENG_AFP_CALLBACK_URL, webHttpUrl, TianchengCallbackEventEnum.SPEED_LOAN_RISK_RULE.getEventType(), cardniuLoanApplyOrderDTO.getProjectId(), FunctionCodeEnum.LIBRA_FRAUD_RISK_RULE.getBodyFunctionCode()));
        riskRuleRequest.setVars(SpeedLoanDubboServiceImpl.getcardNiuVars());
        riskRuleRequest.setFromSource(TCRiskRuleFromSourceEnum.getTCRiskRuleFromSourceByProjectFromSource(ProjectFromSourceEnum.CARD_NIU));
        log.info("发起天称风险规则扫描,标的ID={},请求天称风险规则请求参数={}", cardniuLoanApplyOrderDTO.getProjectId(), riskRuleRequest);
        try {
            CompletableFuture<RiskRuleResponse> result = tianchengAgainstFakeService.riskRule(riskRuleRequest);
            //设置超时时间，如果3秒没有返回就抛异常
            RiskRuleResponse riskRuleResponse = result.get(3, TimeUnit.SECONDS);
            log.info("发起天称风险规则扫描,标的ID={},请求天称风险规则响应结果={}", cardniuLoanApplyOrderDTO.getProjectId(), riskRuleResponse);
//            FlowExecuteDTO flowExecuteDTO = flowExecuteDubboService.selectById(flowExecuteId);
//            flowExecuteDubboService.currNodeExecuteSuccess(AssetFlowTypeEnum.LOAN, AssetFlowNodeTypeEnum.LOAN_RISK_RULES,flowExecuteDTO);
        } catch (Exception e) {
            log.error("发起天称风险规则扫描,标的ID={},发生异常,错误信息={}", cardniuLoanApplyOrderDTO.getProjectId(), e);
//            FlowExecuteDTO flowExecuteDTO = flowExecuteDubboService.selectById(flowExecuteId);
//            flowExecuteDubboService.currNodeExecuteFail(AssetFlowTypeEnum.LOAN, AssetFlowNodeTypeEnum.LOAN_RISK_RULES,flowExecuteDTO,false);
        }
    }

    @Override
    public Integer selectProjectCountBySubStatus(String userId, List<Integer> subStatus) {

        return projectLocalService.selectProjectCountBySubStatus(userId, subStatus);
    }

    @Override
    public Integer queryProjectByStatus(String userId, List<ProjectStatusEnum> statusEnumList){

        return  projectLocalService.queryProjectByStatus(userId, statusEnumList);
    }

	@Override
	public QueryLoanDeviceInfoResponseDTO queryUserLastLoanDeviceInfo(String userId) {
		return transQueryLoanDeviceInfo2DTO(projectCommonService.queryUserLastLoanDeviceInfo(userId));
	}


    /**
     * 查询审核不通过原因
     * @param borrowerUserId
     * @param projectId
     * @return
     */
    public List<String> selectNotPassCause(String borrowerUserId, Long projectId){
        return projectLocalService.selectNotPassCause(borrowerUserId, projectId);
    }
    @Override
    public void addOrgProject(OrgProjectDTO orgProjectDTO) {
        projectLocalService.addOrgProject(orgProjectDTO);
    }

    @Override
    public void pushOrgProject(String orgId, Long orderId) {
        projectLocalService.pushOrgProject(orgId, orderId);
    }

    @Override
    public RefundFreezeParamResponseDTO queryRefundFreezeParam(Long orderId) {
    	 Assert.notNull(orderId, "订单ID不可空");
    	return projectLocalService.queryRefundFreezeParam(orderId);
    }

    @Override
    public void updateProjectStatus(Long projectId){
        Assert.notNull(projectId,"标的ID不可控");
        projectLocalService.updateProjectStatus(projectId);
    }

    @Override
    public Long isNeedSignRepayAgreementContractForOldUser(String userId) {
        List<Project> projectList = projectMapper.selectUnfinishedProjectBeforeSystemRebuildOnline(userId);
        if (projectList != null && projectList.size() > 0) {
            Integer newProjectCount = projectMapper.countProjectAfterSystemRebuildOnline(userId);
            if (newProjectCount == null || newProjectCount <= 0) {
                return projectList.get(0).getProjectId();
            }
        }
        return null;
    }

    @Override
    public Integer queryOutstandingProjectWithoutOrg(String userId) {
        return projectLocalService.queryOutstandingProjectWithoutOrg(userId);
    }

    @Override
    public void projectWaitPublishToPublishScan() {
        projectLocalService.projectWaitPublishToPublishScan();
    }


    /**
     * 统计今日审核通过的标的数量
     *
     * @return
     */
    public Integer countTodayAuditPassProject(){
        return projectLocalService.countTodayAuditPassProject();
    }

    /**
     * 标的重新分端
     * @param projectId
     * @param channelCode
     */
    @Override
    public void resetProjectChannelCode(Long projectId, String channelCode) {
        projectLocalService.resetProjectChannelCode(projectId, channelCode);
    }

    @Override
    public ProjectDetailDTO getProjectById(Long projectId) {
        return projectLocalService.getProjectById(projectId);
    }

    @Override
	public Integer queryMaxDueDays(String userId) {
		return projectLocalService.queryMaxDueDays(userId);
	}

    @Override
	public List<String> queryFromSourceListByUserId(String userId) {
		return projectLocalService.queryFromSourceListByUserId(userId);
	}

    @Override
    public CustomSysBorrowerInfoDTO queryCurrentPeriodRefundInfoByProjectId(Long projectId) {
    	return projectLocalService.queryCurrentPeriodRefundInfoByProjectId(projectId);
    }

    @Override
    public List<CustomSysBorrowerInfoDTO> queryRefundListInfoByProjectId(Long projectId) {
    	return projectLocalService.queryRefundListInfoByProjectId(projectId);
    }

    @Override
    public void setProjectPrizeId(Long projectId, Long prizeId) {
        Assert.notNull(projectId, "projectId不能为空");
        Assert.notNull(prizeId, "prizeId不能为空");
        projectLocalService.setProjectPrizeId(projectId, prizeId);
    }

    @Override
    public void updateOrgProjectStatus(Long projectId, Byte status, Integer subStatus) {
        projectLocalService.updateOrgProjectStatus(projectId, status, subStatus);
    }


}
